// 程序参考来自wifi—robot论坛
#include<reg52.h>
#include<math.h>
#include<intrins.h>

#define uchar unsigned char
#define uint unsigned int

uchar Buffer =0;      //从串口接收的数据
uint URTAReceivedCount=0,n=1;
uchar data Tempdatatable[5],CommandDatatable[5];//数据包
uchar serVal[2];
uint pwm[]={1120,1190,1382,1382,1382,1382,1382,1382}; //初始90度,（实际是1382.4，取整得1382）
uchar pwm_flag=0;
uint code ms0_5Con=461; //0.5ms计数 （实际是460.8，取整得461）
uint code ms2_5Con=2304; //2.5ms计数
bit key_stime_ok;
sbit StatusLight=P2^0; //状态灯
sbit MainLight=P2^1; //主大灯
sbit servo0=P0^0;  //八个舵机控制
sbit servo1=P0^1;
sbit servo2=P0^2;
sbit servo3=P0^3;
sbit servo4=P0^4;
sbit servo5=P0^5;
sbit servo6=P0^6;
sbit servo7=P0^7;
//P1为电机控制端口。

/********************************************************************
* 名称 : Delay_1ms()
* 功能 : 延时子程序，延时时间为 1ms * x
* 输入 : x (延时一毫秒的个数)
* 输出 : 无
***********************************************************************/
void Delay_1ms(uint i)//1ms延时
{
uchar x,j;
for(j=0;j<i;j++)
for(x=0;x<=148;x++); 
}

void TurnOnStatusLight()
{   
   StatusLight=0;
}
/********************************************************************
* 名称 : Send_Data()
* 功能 : 向上位机传送字符
* 输入 : (uchar type,uchar cmd,uchar dat)
* 输出 : 无
***********************************************************************/
void Send_Data(uchar type,uchar cmd,uchar dat)
{ 
   uchar data Buffer[5];//构建数据包
   uchar *p;
   uint Send_Count=0;
   p = Buffer;
   Buffer[0]=0XFF;
   Buffer[1]=type;
   Buffer[2]=cmd;
   Buffer[3]=dat;
   Buffer[4]=0XFF;     
  while(1)
     {
      if(*p==0XFF)
        {
         Send_Count++;  //0XFF标志统计位
        }
      SBUF = *p;  //发送
      while(!TI)  //如果发送完毕，硬件会置位TI，等待发送完毕
           {
             _nop_(); 
           }
      p++;
      TI = 0;
      if(Send_Count == 2)  //当统计到两次出现0XFF，则认为一个数据包发送完毕，跳出循环
        {
         TI = 0;
         break;
        }  
     }
}
/********************************************************************
协议规定：
包头  类型位  数据位 数据位   结束位
0XFF   0X**   OX**   0X**      0XFF
各命令说明：
类型位   数据位  数据位  功能


0X00       0X02  0X00    前进
0X00       0X01  0X00    后退
0X00       0X03  0X00    左转
0X00       0X04  0X00    右转
0X00       0X00  0X00    停止

0X01       0X01  角度    舵机1
0X01       0X02  数据     舵机2


0X02       0X01     车灯亮
0X02       0X02     车灯灭

***********************************************************************/
/********************************************************************
* 名称 : Com_Int()
* 功能 : 串口中断子函数
***********************************************************************/
void Com_Int(void) interrupt 4
{
uchar temp;
ES=0; //关串口中断
RI=0; //软件清除接收中断
temp=SBUF;
  if(temp==0XFF && URTAReceivedCount<3)
     {
       Tempdatatable[0]==0XFF;  //包头
       URTAReceivedCount++;
     }
  else
     { 
       Tempdatatable[n]=temp;
       n++;
	   if(URTAReceivedCount==0&&n==2) 
	   n=1;
     }

  if(URTAReceivedCount==2)//包尾
    {
       Tempdatatable[0]=0XFF;
       Tempdatatable[4]=0XFF;
       n=1;
       URTAReceivedCount=0;  //组包完毕
       temp=0;
//       Send_Data(Tempdatatable[1],Tempdatatable[2],Tempdatatable[3]);  //发送组成的数据包回去
    }

  CommandDatatable[0]=Tempdatatable[0];
  CommandDatatable[1]=Tempdatatable[1];
  CommandDatatable[2]=Tempdatatable[2];
  CommandDatatable[3]=Tempdatatable[3];
  CommandDatatable[4]=Tempdatatable[4];

  ES=1;//开串口中断
  

}

/********************************************************************
* 名称 : Com_Init()
* 功能 : 串口初始化，晶振11.0592,波特率9600，使能了串口中断
***********************************************************************/
void Com_Init(void)
{
     TMOD = 0x21;
     PCON = 0x00;
     SCON = 0x50;   
     TH1 = 0xFd;    //设置波特率 9600
     TL1 = 0xFd;
     TR1 = 1;  //启动定时器1
     ES = 1;  //开串口中断
     EA = 1;  //开总中断 
     IT0=0;
     EX0=1; 
}

/********************************************************************
* 名称 :Moto_Forward()
* 功能 : 电机1、2启动，都是前进，整车表现为前进。
***********************************************************************/
void Moto_Forward()
{  
   P1= 0x06;
   Delay_1ms(100);
}
/********************************************************************
* 名称 :Moto_Backward()
* 功能 : 电机1、2启动，都是后退，整车表现为后退。
***********************************************************************/
void Moto_Backward()
{
  
  P1= 0x09;
  Delay_1ms(100);
}

/********************************************************************
* 名称 :Moto_TurnLeft()
* 功能 : 电机1后退，电机2前进，整车表现为左转。
***********************************************************************/
void Moto_TurnLeft()
{ 
   P1= 0x0a;
   Delay_1ms(100);
}
/********************************************************************
* 名称 :Moto_TurnRight()
* 功能 : 电机1前进，电机2后退，整车表现为右转。
***********************************************************************/
void Moto_TurnRight()
{ 
  P1= 0x05;
  Delay_1ms(100);
}
/********************************************************************
* 名称 :Moto_Stop()
* 功能 : 电机1停止，电机2停止，整车表现为停止。
***********************************************************************/
void Moto_Stop()
{ 

   P1= 0x00;
   Delay_1ms(100);
}
/********************************************************************
* 功能 : 舵机PWM中断初始化
***********************************************************************/
void Timer0Init()
  {
      /*0度=0.5ms, 45度=1ms, 90度=1.5ms, 135度=2ms, 180度=2.5ms
      /.5 ms初始值 F700, (12n/11059200=2.5/1000, n=2304, X=65536-2304=63232 > F700)*/  
	TMOD |= 0x01;	  //使用模式1，16位定时器，使用"|"符号可以在使用多个定时器时不受影响		
	TH0=-ms2_5Con>>8;	      //给定初值，17ms中断
	TL0=-ms2_5Con;
	EA=1;            //总中断打开
	ET0=1;           //定时器0中断打开
	TR0=1;           //定时器0开关打开                                   
  }
/********************************************************************
* 功能 : 舵机PWM中断, //舵机控制函数 周期为20ms 一个循环20MS  = 8*2.5ms 
***********************************************************************/
void SteeringGear() interrupt 1
{
    switch(pwm_flag)
    {
        case 1:  servo0=1; TH0=-pwm[0]>>8; TL0=-pwm[0]; break;
        case 2:  servo0=0; TH0=-(ms2_5Con-pwm[0])>>8; TL0=-(ms2_5Con-pwm[0]); break;
		case 3:  servo1=1; TH0=-pwm[1]>>8; TL0=-pwm[1]; break;
        case 4:  servo1=0; TH0=-(ms2_5Con-pwm[1])>>8; TL0=-(ms2_5Con-pwm[1]); break;   
		case 5:  servo2=1; TH0=-pwm[2]>>8; TL0=-pwm[2]; break;
        case 6:  servo2=0; TH0=-(ms2_5Con-pwm[2])>>8; TL0=-(ms2_5Con-pwm[2]); break;
		case 7:  servo3=1; TH0=-pwm[3]>>8; TL0=-pwm[3]; break;
        case 8:  servo3=0; TH0=-(ms2_5Con-pwm[3])>>8; TL0=-(ms2_5Con-pwm[3]); break;
		case 9:  servo4=1; TH0=-pwm[4]>>8; TL0=-pwm[4]; break;
        case 10: servo4=0; TH0=-(ms2_5Con-pwm[4])>>8; TL0=-(ms2_5Con-pwm[4]); break;
        case 11: servo5=1; TH0=-pwm[5]>>8; TL0=-pwm[5]; break;
        case 12: servo5=0; TH0=-(ms2_5Con-pwm[5])>>8; TL0=-(ms2_5Con-pwm[5]); break;
		case 13: servo6=1;TH0=-pwm[6]>>8; TL0=-pwm[6]; break;                      
        case 14: servo6=0;TH0=-(ms2_5Con-pwm[6])>>8; TL0=-(ms2_5Con-pwm[6]); break;  
        case 15: servo7=1;TH0=-pwm[7]>>8;  TL0=-pwm[7]; break;      
        case 16: servo7=0;TH0=-(ms2_5Con-pwm[7])>>8; TL0=-(ms2_5Con-pwm[7]); break; 
		default: TH0=0xff; TL0=0x80; pwm_flag=0;          
  }
    pwm_flag++;
}

  void SetSteeringGear(uchar i, uchar val)
{
	uint a = (val+46)*10;
    if(a<ms0_5Con)
		a=ms0_5Con;
	if(a>ms2_5Con)
		a=ms2_5Con;
	pwm[i]=a;
	CommandDatatable[2]=0xff; //清除缓存
}

/********************************************************************
* 功能 : 串口中断接收数据
***********************************************************************/

 
/*********************************************************************************
** 函数功能 ： 主函数
*********************************************************************************/

void main()
{    
  
    MainLight=0;
    Delay_1ms(200);
    Com_Init();//串口初始化
    Timer0Init();//舵机PWM中断初始化    
  while(1)
  {
  
   if(CommandDatatable[0]==0XFF && CommandDatatable[4]==0XFF)
      {
           switch (CommandDatatable[1])      //根据键值不同，执行不同的内容
             {
              case 0X00:  //类型位0X00，表明是控制数据包，进入控制数据case
                  switch(CommandDatatable[2])  //根据数据位的值来进行选择执行不同的动作
                           {
                             case 0X00:Moto_Stop();break;
                             case 0X01:Moto_Forward();break;
                             case 0X02:Moto_Backward();break;
                             case 0X03:Moto_TurnLeft();break;
                             case 0X04:Moto_TurnRight();break; 
							 default :  break;
                           }
                         break;
              case 0X01:    //类型位0X01，表明是舵机数据包，进入舵机case  
                  switch(CommandDatatable[2])
                 {          
	                case 0x01:SetSteeringGear(0,CommandDatatable[3]);break;
		            case 0x02:SetSteeringGear(1,CommandDatatable[3]);break;
		            case 0x03:SetSteeringGear(2,CommandDatatable[3]);break;
		            case 0x04:SetSteeringGear(3,CommandDatatable[3]);break;
	            	case 0x05:SetSteeringGear(4,CommandDatatable[3]);break;
	            	case 0x06:SetSteeringGear(5,CommandDatatable[3]);break;
					case 0x07:SetSteeringGear(6,CommandDatatable[3]);break;
	            	case 0x08:SetSteeringGear(7,CommandDatatable[3]);break;
		 			default :  break;
                      }
                     break;
              case 0X02:  //类型位0X02，表明是大灯数据包，进入大灯case
                  switch(CommandDatatable[2])
                           {
                             case 0X01:MainLight=1;break;
                             case 0X02:MainLight=0;break;
							 default :  break;
                           }
                  break;
              default :  break;
            }
       }
  }
}